package com.example.dbsample.config.database;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.dbsample.config.business.BaseSwitchConfig;
import com.example.dbsample.model.constants.DataSourceConstants;
import com.example.dbsample.util.worker.WorkerIdAssigner;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * 该数据源默认不开启，原因是不通过这种方式开启
 */
//@Configuration
@Slf4j
@ConditionalOnMissingBean(value = PgAutoSecondConfiguration.class, name = "pgAutoSecondConfiguration") // 这个无实际意义，只是为了说明用法
@MapperScan(basePackages = {"com.example.*.secondmapper"}, sqlSessionFactoryRef = PgAutoSecondConfiguration.SQL_SESSION_FACtOY_CONSUMER_FINANCE)
@ConditionalOnBean(value = {DataSourceSecondConfig.class}, name = {"dataSourceSecondConfig"})          // 这个无实际意义，只是为了说明用法
public class PgAutoSecondConfiguration {
    public static final String DATASOURCE_CONSUMER_FINANCE = "dataSourceSecond";
    public static final String SQL_SESSION_FACtOY_CONSUMER_FINANCE = "sqlSessionFactorySecond";
    private static final String TRANSACTION_MANAGER_CONSUMER_FINANCE = "transactionManagerSecond";
    private static final String SQL_SESSION_TEMPLATE_FINANCE = "sqlSessionTemplateSecond";

    @Autowired(required = false)
    private WorkerIdAssigner workerIdAssigner;

    @Autowired
    private BaseSwitchConfig baseSwitchConfig;

    @Bean
    public DataSourceSecondConfig getDataSourceSecondConfig() {
        return new DataSourceSecondConfig();
    }

    @Autowired
    private DataSourceSecondConfig dataSourceSecondConfig;

    @Autowired
    MybatisPlusInterceptor mybatisPlusInterceptor;

    /**
     * 用完即弃的WorkerIdAssigner，依赖DB操作
     */
    //@Bean
    //public CachedUidGenerator cachedUidGenerator() {
    //    CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
    //    if(workerIdAssigner == null) {
    //        if(baseSwitchConfig.isEnableRadomWorkId()) {
    //            workerIdAssigner = new RandomWorkerIdAssigner();
    //        } else {
    //            throw new BusinessException("请实现WorkerIdAssigner");
    //        }
    //    }
    //
    //    cachedUidGenerator.setWorkerIdAssigner((workerIdAssigner));
    //
    //    // 以下为可选配置，入围知道将采用默认值
    //    cachedUidGenerator.setTimeBits(29);
    //    cachedUidGenerator.setWorkerBits(21);
    //    cachedUidGenerator.setSeqBits(13);
    //    cachedUidGenerator.setEpochStr("2023-04-07");
    //
    //    // RingBuffer size扩容参数，可提高UID生成的吞吐量
    //    // 默认：3，院bufferSize=8192，扩容后bufferSize=8192 << 3 = 65536
    //    cachedUidGenerator.setBoostPower(3);
    //
    //    /**
    //     * 指定核酸想RingBuffer中扩充UID，取值为百分比（0, 100）,默认为50
    //     * 举例：bufferSize=1024，paddingFactor=50 -> threshold=1024 * 50 / 100 = 512
    //     * 当换上可用UID数量 < 512时，将自动对RingBuffer进行填充补全
    //     * 另外一种RingBuffer填充时机，在Schedule线程中，周期性检查填充
    //     * 默认：不配置此项，即不使用Schedule线程，如需使用，请指定Schedule线程时间间隔，单位：秒
    //     */
    //    // cachedUidGenerator.setScheduleInterval(60L);
    //
    //    return cachedUidGenerator;
    //}

    @Bean(value = DATASOURCE_CONSUMER_FINANCE)
    @Primary
    public DataSource dataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(dataSourceSecondConfig.getUrl());
        druidDataSource.setUsername(dataSourceSecondConfig.getUsername());
        druidDataSource.setPassword(dataSourceSecondConfig.getPassword());
        druidDataSource.setDriverClassName(dataSourceSecondConfig.getDriverClassName());
        druidDataSource.setInitialSize(dataSourceSecondConfig.getInitialSize());
        druidDataSource.setMinIdle(dataSourceSecondConfig.getMinIdle());

        druidDataSource.setMaxActive(Integer.valueOf(dataSourceSecondConfig.getMaxActive()));
        druidDataSource.setMaxWait(dataSourceSecondConfig.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(dataSourceSecondConfig.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(dataSourceSecondConfig.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(dataSourceSecondConfig.getValidationQuery());
        druidDataSource.setTestWhileIdle(dataSourceSecondConfig.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(dataSourceSecondConfig.isTestOnBorrow());
        druidDataSource.setTestOnReturn(dataSourceSecondConfig.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(dataSourceSecondConfig.isPoolPreparedStatements());
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(dataSourceSecondConfig.getMaxPoolPreparedStatementPerConnectionSize());

        try {
            druidDataSource.setFilters(dataSourceSecondConfig.getFilters());
        } catch (SQLException e) {
            log.error("druid datasource second configuration initialize failed", e);
        }

        log.info("druid datasource second configuration initialize succeeded");
        return druidDataSource;
    }

    @Bean(value = SQL_SESSION_FACtOY_CONSUMER_FINANCE)
    @Primary
    public SqlSessionFactory sqlSessionFactorySecond(@Qualifier(DATASOURCE_CONSUMER_FINANCE) DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // TODO 不能用：getResources，它只能用单个文件，不能用通配符*
        factoryBean.setMapperLocations(resolver.getResources(DataSourceConstants.XML_LOCATION_PATTERN));
        factoryBean.setTypeAliasesPackage(DataSourceConstants.TYPE_ALIASES_PACKAGE);

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        factoryBean.setConfiguration(configuration);

        // 注：要在这里加载分页插件，否则不生效
        Interceptor[] plugins = {mybatisPlusInterceptor};
        factoryBean.setPlugins(plugins);

        return factoryBean.getObject();
    }

    @Bean(value = TRANSACTION_MANAGER_CONSUMER_FINANCE)
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier(DATASOURCE_CONSUMER_FINANCE) DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(value = SQL_SESSION_TEMPLATE_FINANCE)
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier(SQL_SESSION_FACtOY_CONSUMER_FINANCE) SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
